<script lang="ts" setup>
import type { UploadFile, UploadProps } from 'ant-design-vue';

import { ref, watch } from 'vue';

import { useVbenModal } from '@vben/common-ui';
import { IconifyIcon } from '@vben/icons';
import { isObject, isString } from '@vben/utils';

import { Button, message, Modal, Upload } from 'ant-design-vue';

import { useUpload } from '#/components/upload/use-upload';

import DressCropperModal from './dress-cropper-modal.vue';

interface Props {
  value?: string[];
  maxCount?: number;
  maxSize?: number;
  disabled?: boolean;
}

const props = withDefaults(defineProps<Props>(), {
  value: () => [],
  maxCount: 5,
  maxSize: 5,
  disabled: false,
});

defineOptions({ name: 'DressImageUpload' });

const emit = defineEmits(['update:value', 'change']);

const fileList = ref<UploadProps['fileList']>([]);
const isInnerOperate = ref(false);
const previewOpen = ref(false);
const previewImage = ref('');
const previewTitle = ref('');
const pendingFile = ref<null | File>(null);

// 裁剪弹窗
const [CropperModalComponent, cropperModalApi] = useVbenModal({
  connectedComponent: DressCropperModal,
});

// 初始化文件列表
watch(
  () => props.value,
  (v) => {
    if (isInnerOperate.value) {
      isInnerOperate.value = false;
      return;
    }
    const newFileList: UploadFile[] = [];
    if (v && Array.isArray(v)) {
      for (const [i, item] of v.entries()) {
        const urlItem =
          item && isString(item)
            ? {
                uid: `${-i}`,
                name: item.slice(Math.max(0, item.lastIndexOf('/') + 1)),
                status: 'done' as const,
                url: item,
              }
            : item && isObject(item)
              ? (item as unknown as UploadFile)
              : null;

        if (urlItem) {
          newFileList.push(urlItem);
        }
      }
    }
    fileList.value = newFileList;
  },
  { immediate: true },
);

// 图片预览
async function handlePreview(file: UploadFile) {
  if (!file.url && !file.preview && file.originFileObj) {
    file.preview = await getBase64(file.originFileObj);
  }
  previewImage.value = file.url || file.preview || '';
  previewOpen.value = true;
  previewTitle.value =
    file.name ||
    previewImage.value.slice(
      Math.max(0, previewImage.value.lastIndexOf('/') + 1),
    );
}

function handleCancelPreview() {
  previewOpen.value = false;
  previewTitle.value = '';
}

function getBase64(file: File): Promise<string> {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.readAsDataURL(file);
    reader.addEventListener('load', () => resolve(reader.result as string));
    reader.addEventListener('error', (error) => reject(error));
  });
}

// 编辑图片
async function handleEdit(file: UploadFile) {
  const imageUrl = file.url || file.preview || '';
  
  cropperModalApi
    .setData({
      src: imageUrl,
      uploadApi: handleCropperUpload,
      size: props.maxSize,
      editingFile: file,
    })
    .open();
}

// 裁剪后上传
async function handleCropperUpload({
  file,
  filename,
}: {
  file: Blob;
  filename: string;
}) {
  const { httpRequest } = useUpload();
  const fileObj = new File([file], filename, { type: file.type });
  const editingFile = cropperModalApi.getData<any>()?.editingFile;

  try {
    cropperModalApi.setState({ confirmLoading: true });
    const result = await httpRequest(fileObj);

    // 更新文件列表中对应的图片
    if (editingFile && fileList.value) {
      const index = fileList.value.findIndex(
        (item) => item.uid === editingFile.uid,
      );
      if (index !== -1 && fileList.value[index]) {
        const currentFile = fileList.value[index];
        fileList.value[index] = {
          ...currentFile,
          uid: currentFile.uid,
          url: result.url,
          status: 'done',
          response: result,
          name: filename,
        };
      }
    }

    // 更新值
    const value = getValue();
    isInnerOperate.value = true;
    emit('update:value', value);
    emit('change', value);

    message.success('编辑成功!');
    cropperModalApi.close();
    return result.url;
  } catch (error) {
    message.error('编辑失败!');
    throw error;
  } finally {
    cropperModalApi.setState({ confirmLoading: false });
  }
}

// 删除图片
async function handleRemove(file: UploadFile) {
  if (fileList.value) {
    const index = fileList.value.findIndex((item) => item.uid === file.uid);
    if (index !== -1) {
      fileList.value.splice(index, 1);
      const value = getValue();
      isInnerOperate.value = true;
      emit('update:value', value);
      emit('change', value);
    }
  }
}

// 上传前验证 - 阻止自动上传，先进入裁剪模式
function beforeUpload(file: File) {
  const isImage = file.type.startsWith('image/');
  if (!isImage) {
    message.error('只能上传图片文件!');
    return Upload.LIST_IGNORE;
  }

  const isLt = file.size / 1024 / 1024 < props.maxSize;
  if (!isLt) {
    message.error(`图片大小不能超过 ${props.maxSize}MB!`);
    return Upload.LIST_IGNORE;
  }

  // 检查是否超过最大数量
  if (fileList.value && fileList.value.length >= props.maxCount) {
    message.error(`最多只能上传 ${props.maxCount} 张图片!`);
    return Upload.LIST_IGNORE;
  }

  // 保存待处理的文件，进入裁剪模式
  pendingFile.value = file;
  
  // 读取文件并打开裁剪弹窗
  const reader = new FileReader();
  reader.readAsDataURL(file);
  reader.addEventListener('load', (e) => {
    const imageUrl = e.target?.result as string;
    cropperModalApi
      .setData({
        src: imageUrl,
        uploadApi: handleNewImageUpload,
        size: props.maxSize,
        filename: file.name,
      })
      .open();
  });

  // 阻止自动上传
  return Upload.LIST_IGNORE;
}

// 新图片裁剪后上传
async function handleNewImageUpload({
  file,
  filename,
}: {
  file: Blob;
  filename: string;
}) {
  const { httpRequest } = useUpload();
  const fileObj = new File([file], filename, { type: file.type });

  try {
    cropperModalApi.setState({ confirmLoading: true });
    const result = await httpRequest(fileObj);

    // 添加到文件列表
    const newFile: UploadFile = {
      uid: Date.now().toString(),
      name: filename,
      status: 'done',
      url: result.url,
      response: result,
    };

    if (!fileList.value) {
      fileList.value = [];
    }
    fileList.value.push(newFile);

    // 更新值
    const value = getValue();
    isInnerOperate.value = true;
    emit('update:value', value);
    emit('change', value);

    message.success('上传成功!');
    cropperModalApi.close();
    pendingFile.value = null;
    return result.url;
  } catch (error) {
    message.error('上传失败!');
    throw error;
  } finally {
    cropperModalApi.setState({ confirmLoading: false });
  }
}

// 获取值
function getValue(): string[] {
  return (fileList.value || [])
    .filter((item) => item?.status === 'done')
    .map((item) => {
      if (item?.response) {
        return (item.response as any).url || item.response;
      }
      return item?.url || '';
    })
    .filter(Boolean);
}
</script>

<template>
  <div>
    <Upload
      v-model:file-list="fileList"
      :before-upload="beforeUpload"
      :disabled="disabled"
      accept="image/*"
      list-type="picture-card"
      :max-count="maxCount"
      :multiple="true"
      :show-upload-list="{
        showPreviewIcon: true,
        showRemoveIcon: !disabled,
      }"
      @preview="handlePreview"
      @remove="handleRemove"
    >
      <template #itemRender="{ file, actions }">
        <div class="relative">
          <div class="ant-upload-list-item-info">
            <span class="ant-upload-span">
              <img
                :alt="file.name"
                :src="file.url || file.thumbUrl"
                class="ant-upload-list-item-image"
              />
            </span>
          </div>
          <div v-if="!disabled" class="ant-upload-list-item-actions">
            <Button
              class="ant-upload-list-item-card-actions-btn"
              size="small"
              type="text"
              @click="handlePreview(file)"
              title="预览"
            >
              <IconifyIcon icon="lucide:eye" />
            </Button>
            <Button
              class="ant-upload-list-item-card-actions-btn"
              size="small"
              type="text"
              @click="handleEdit(file)"
              title="编辑裁剪"
            >
              <IconifyIcon icon="lucide:scissors" />
            </Button>
            <Button
              class="ant-upload-list-item-card-actions-btn"
              danger
              size="small"
              type="text"
              @click="actions.remove"
              title="删除"
            >
              <IconifyIcon icon="lucide:trash-2" />
            </Button>
          </div>
        </div>
      </template>

      <div
        v-if="fileList && fileList.length < maxCount"
        class="flex flex-col items-center justify-center"
      >
        <IconifyIcon class="text-2xl" icon="lucide:cloud-upload" />
        <div class="mt-1 text-xs">选择图片</div>
      </div>
    </Upload>

    <div class="mt-2 rounded-lg bg-blue-50 p-3 text-sm text-blue-700">
      <div class="flex items-start gap-2">
        <IconifyIcon icon="lucide:info" class="mt-0.5 flex-shrink-0" />
        <div>
          <div class="mb-1 font-medium">上传说明</div>
          <div class="space-y-1 text-xs">
            <div>• 支持 JPG、PNG、GIF、WEBP 格式</div>
            <div>
              • 最多上传 <span class="font-semibold">{{ maxCount }}</span> 张，每张不超过
              <span class="font-semibold">{{ maxSize }}MB</span>
            </div>
            <div>
              • 选择图片后会自动进入裁剪编辑模式
            </div>
            <div>
              • 鼠标悬停在图片上可看到编辑按钮：
              <IconifyIcon icon="lucide:eye" class="inline" /> 预览、
              <IconifyIcon icon="lucide:scissors" class="inline" /> 编辑、
              <IconifyIcon icon="lucide:trash-2" class="inline" /> 删除
            </div>
            <div class="font-medium text-blue-600">
              • 建议使用统一比例裁剪，保持图片风格一致
            </div>
          </div>
        </div>
      </div>
    </div>

    <!-- 预览弹窗 -->
    <Modal
      :footer="null"
      :open="previewOpen"
      :title="previewTitle"
      @cancel="handleCancelPreview"
    >
      <img alt="preview" :src="previewImage" class="w-full" />
    </Modal>

    <!-- 裁剪弹窗 -->
    <CropperModalComponent @upload-success="() => {}" />
  </div>
</template>

<style scoped>
:deep(.ant-upload-select-picture-card) {
  @apply flex items-center justify-center;
}

:deep(.ant-upload-list-picture-card-container) {
  @apply inline-block;
}

:deep(.ant-upload-list-item-info) {
  @apply relative overflow-hidden rounded;
}

:deep(.ant-upload-list-item-actions) {
  @apply absolute inset-0 flex items-center justify-center gap-2 bg-black/50 opacity-0 transition-opacity;
}

:deep(.ant-upload-list-item-info:hover + .ant-upload-list-item-actions),
:deep(.ant-upload-list-item-actions:hover) {
  @apply opacity-100;
}

/* 确保按钮在正确位置显示 */
:deep(.ant-upload-list-picture-card-container) {
  @apply relative;
}

:deep(.ant-upload-list-picture-card-container:hover .ant-upload-list-item-actions) {
  @apply opacity-100;
}

:deep(.ant-upload-list-item-card-actions-btn) {
  @apply hover:text-primary text-white;
}

:deep(.ant-upload-list-item-image) {
  @apply h-full w-full object-cover;
}
</style>
